package com.geovis.emergency.spd.biz.zwdd.handler;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.xxpt.gateway.shared.api.request.*;
import com.alibaba.xxpt.gateway.shared.api.response.*;
import com.alibaba.xxpt.gateway.shared.client.http.ExecutableClient;
import com.alibaba.xxpt.gateway.shared.client.http.IntelligentGetClient;
import com.alibaba.xxpt.gateway.shared.client.http.IntelligentPostClient;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.geovis.common.auth.util.AuthUtil;
import com.geovis.common.core.constant.CommonConstants;
import com.geovis.common.core.util.SpringContextHolder;
import com.geovis.emergency.spd.biz.system.service.*;
import com.geovis.emergency.spd.biz.zwdd.props.ZwddProperties;
import com.geovis.emergency.spd.entity.pc.entity.PcPlanDutyOrgDept;
import com.geovis.emergency.spd.entity.system.entity.*;
import com.geovis.emergency.spd.entity.system.pojo.enums.RoleTypeEnum;
import com.geovis.emergency.spd.entity.zwdd.pojo.*;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 海证通同步处理类
 * </p>
 *
 * @author 王响
 * @since 2022-03-16
 */
@Getter
@Setter
@Slf4j
public class ZwddSynchronizeHandler implements Serializable {

    /**
     * 海证通得请求客户端
     */
    private final ExecutableClient executableClient;

    /**
     * 海证通的配置
     */
    private final ZwddProperties zwddProperties;

    /**
     * 删除未更新数据时回退的时间
     */
    private final Duration RM_BACK_TIME;

    /**
     * 批量获取的最大数量
     */
    private final Integer MAX_SIZE;

    /**
     * 批量保存最大数量
     */
    private final Integer BATCH_MAX_SIZE;

    /**
     * 生成的组织
     */
    private final CopyOnWriteArrayList<SystemDept> systemDeptList;
    /**
     * 生成的员工
     */
    private final CopyOnWriteArrayList<SystemUser> systemUserList;
    /**
     * 生成的员工组织关联信息
     */
    private final CopyOnWriteArrayList<SystemDeptUser> systemDeptUserList;
    /**
     * 生成的部门锁
     */
    private final Lock systemDeptLock;
    /**
     * 生成的员工锁
     */
    private final Lock systemUserLock;
    /**
     * 生成的员工组织关联信息锁
     */
    private final Lock systemDeptUserLock;


    /**
     * 构造器
     */
    public ZwddSynchronizeHandler(ExecutableClient executableClient, ZwddProperties zwddProperties) {
        this(executableClient, zwddProperties, Duration.ofDays(7), 64, 1000);
    }

    /**
     * 构造器
     */
    public ZwddSynchronizeHandler(ExecutableClient executableClient, ZwddProperties zwddProperties, Duration rmBackTime) {
        this(executableClient, zwddProperties, rmBackTime, 64, 1000);
    }

    /**
     * 构造器
     */
    public ZwddSynchronizeHandler(ExecutableClient executableClient, ZwddProperties zwddProperties, int maxSize, int bashMaxSize) {
        this(executableClient, zwddProperties, Duration.ofDays(7), maxSize, bashMaxSize);
    }

    /**
     * 构造器
     */
    public ZwddSynchronizeHandler(ExecutableClient executableClient, ZwddProperties zwddProperties, Duration rmBackTime, int maxSize, int bashMaxSize) {
        this.executableClient = executableClient;
        this.zwddProperties = zwddProperties;
        this.RM_BACK_TIME = rmBackTime;
        this.MAX_SIZE = maxSize;
        this.BATCH_MAX_SIZE = bashMaxSize;
        this.systemDeptList = CollUtil.newCopyOnWriteArrayList(Collections.emptyList());
        this.systemUserList = CollUtil.newCopyOnWriteArrayList(Collections.emptyList());
        this.systemDeptUserList = CollUtil.newCopyOnWriteArrayList(Collections.emptyList());
        this.systemDeptLock = new ReentrantLock();
        this.systemUserLock = new ReentrantLock();
        this.systemDeptUserLock = new ReentrantLock();
    }


    /**
     * 同步通讯录（所有）
     */
    public void synchronize() {
        synchronize(false, false);
    }

    /**
     * 删除用户角色关系表
     */
    private void delAllUserRoles()
    {
        SpringContextHolder.getBean(ISystemUserRoleService.class).remove(Wrappers.lambdaQuery(SystemUserRole.class));
    }

    /**
     * 同步通讯录（所有）
     *
     * @param removeOldDeptAndUser 是否清除旧组织机构信息和相关用户信息
     * @param removeOldUser        是否清除旧的用户信息
     */
    public void synchronize(boolean removeOldDeptAndUser, boolean removeOldUser) {
        log.info("-------开始同步--------");
        LocalDateTime startTime = LocalDateTime.now();
        LocalDateTime rmBeforeDateTime = startTime.minus(RM_BACK_TIME);
        // 同步所有组织机构
        OapiAuthScopesV2ResponseContent oapiAuthScopesV2ResponseContent = getScopesV2();
        if (null == oapiAuthScopesV2ResponseContent) {
            log.error("OapiAuthScopesV2ResponseContent为空");
            return;
        }
        // 先同步条线组织，防止根节点属性被覆盖
        // 同步条线组织机构
        List<StripLineAddressScope> stripLineAddressScopes = oapiAuthScopesV2ResponseContent.getStripLineAddressScopes();
        if (!CollectionUtils.isEmpty(stripLineAddressScopes)) {
            initStripLineOrganizationCodeList(stripLineAddressScopes, true);
        }
        // 同步组织机构
        List<String> deptVisibleScopes = oapiAuthScopesV2ResponseContent.getDeptVisibleScopes();
        if (!CollectionUtils.isEmpty(deptVisibleScopes)) {
            initOrganizationCodeList(deptVisibleScopes, true);
        }
        this.batchSystemDept(true);
        log.info("-------同步部门完成--------");
        // 同步组织用户
        List<SystemDept> organList = SpringContextHolder.getBean(ISystemDeptService.class).list();
        organList.stream().parallel().forEach(organization -> {
            String organizationCode = organization.getId();
            int pageNo = 1;
            List<Employee> employeeList;
            List<EmployeeAccount> employeeAccountList;
            List<OrgEmployeePosition> orgEmployeePositions;
            do {
                employeeList = pageEmployeeByOrganizationCodeList(pageNo++, organizationCode);
                if (CollUtil.isEmpty(employeeList)) {
                    break;
                }
                List<String> employeeCodes = employeeList.stream().parallel().map(Employee::getEmployeeCode).collect(Collectors.toList());
                employeeAccountList = this.listEmployeeAccountIdList(employeeCodes);
                orgEmployeePositions = this.listGovEmployeePositions(organizationCode, employeeCodes);
                this.buildAndSaveSystemUser(organizationCode, employeeList, employeeAccountList, orgEmployeePositions);
            } while (CollUtil.isNotEmpty(employeeList));
        });
        this.batchSystemUser(true);
        log.info("-------同步用户结束--------");
        this.batchSystemDeptUser(true);
        //处理用户角色
        log.info("-------保存用户角色开始--------");
        saveUserRole();
        log.info("-------保存用户角色结束--------");
        // 更新组织用户主要部门/职位信息
        this.updateSystemUserJobFinal();

        // 旧数据清除，！！！最后执行！！！
        if (removeOldDeptAndUser) {
            // 清除过旧的组织机构信息和相关用户信息
            this.removeOldSystemDeptAndUser(rmBeforeDateTime);
        }
        if (removeOldUser) {
            // 清除过旧的用户信息
            this.removeOldSystemUser(rmBeforeDateTime);
        }

        Duration taskTime = Duration.between(startTime, LocalDateTime.now());
        log.info("同步完成！！！执行参数：removeOldDeptAndUser={}，removeOldUser={}，花费时间：{}", removeOldDeptAndUser, removeOldUser, taskTime.toString());
    }


    // =============== 内部同步方法 ===============


    /**
     * <p>
     * 1、根据机构编码获取详细机构信息
     * 2、分页遍历下级机构
     * 3、如果是叶子节点就初始化用户信息
     * </p>
     *
     * @param organizationCodeList 组织编号集合
     * @param root                 是否根节点
     */
    private void initOrganizationCodeList(List<String> organizationCodeList, boolean root) {
        if (ObjectUtil.isEmpty(organizationCodeList)) {
            log.debug("organizationCodeList为空");
            return;
        }
        // 1、根据机构编码获取详细机构信息
        List<Organization> organizationList = getOrganizationByCodeList(organizationCodeList);
        organizationList.stream().parallel().forEach(organization -> {
            log.debug(organization.getOrganizationName());
            this.buildSystemDept(organization, root);
            // 2、分页遍历下级机构
            int pageNo = 1;
            int organizationCodeListSize = MAX_SIZE;
            while (organizationCodeListSize == MAX_SIZE) {
                List<String> subOrganizationCodeList = pageSubOrganizationCodeList(pageNo++, organization.getOrganizationCode());

                // 获取详细的机构信息
                this.initOrganizationCodeList(subOrganizationCodeList, false);

                organizationCodeListSize = subOrganizationCodeList.size();
            }
        });
    }

    /**
     * 1、根据机构编码获取详细机构信息
     * 2、分页遍历下级机构
     * 3、如果是叶子节点就初始化用户信息
     *
     * @param stripLineAddressScopes 条线组织集合
     * @param root                   是否根节点
     */
    private void initStripLineOrganizationCodeList(List<StripLineAddressScope> stripLineAddressScopes, boolean root) {
        if (ObjectUtil.isEmpty(stripLineAddressScopes)) {
            log.debug("stripLineAddressScopes为空");
            return;
        }
        // 1、获取条线组织最终关联的组织编号
        CopyOnWriteArrayList<String> organizationCodes = CollUtil.newCopyOnWriteArrayList(Collections.emptyList());
        // 转换为条线组织
        List<StripLineOrganization> stripLineOrganizations = stripLineAddressScopes.stream().parallel()
                .flatMap(slas -> {
                    String dc = slas.getDomainCode();
                    List<String> stripLineAddressCodes = slas.getStripLineAddressCodes();
                    if (!StringUtils.hasText(dc)) {
                        return Stream.empty();
                    }
                    if (CollectionUtils.isEmpty(stripLineAddressCodes)) {
                        return Stream.empty();
                    }
                    return stripLineAddressCodes.stream().map(slac -> getStripLineOrganizationByCode(dc, slac));
                }).collect(Collectors.toList());
        AtomicBoolean isRoot = new AtomicBoolean(root);
        do {
            // 为了保证条线组织的顺序，不开启多线程创建/更新
            stripLineOrganizations = stripLineOrganizations.stream()
                    // 保存条线组织，当前已知不会与组织编号重复
                    .peek(slo -> buildSystemDept(slo, isRoot.get()))
                    .filter(slo -> {
                        String refOrganizationCode = slo.getRefOrganizationCode();
                        if (!StringUtils.hasText(refOrganizationCode)) {
                            return true;
                        }
                        // 引用的区划组织code后无子条线组织
                        // 添加进待更新组织集合
                        //这里和门户处理不一样，因为预案系统不考虑行政区划的场景
                        buildSystemDept(slo,isRoot.get());
                        organizationCodes.add(refOrganizationCode);
                        return false;
                    }).flatMap(slo -> {
                        // 查询子条线组织
                        List<StripLineOrganization> slos = CollUtil.list(true);
                        List<StripLineOrganization> slosTemp = null;
                        int pageNo = 1;
                        int size = MAX_SIZE;
                        while (size == MAX_SIZE) {
                            slosTemp = pageSubStripLineOrganizationCodeList(pageNo++, slo.getDomainCode(), slo.getOrganizationCode());
                            slos.addAll(slosTemp);
                            size = slosTemp.size();
                        }
                        return slos.stream();
                    }).collect(Collectors.toList());
            // 后续都是子节点
            isRoot.compareAndSet(root, false);
        } while (!CollectionUtils.isEmpty(stripLineOrganizations));
        // 为了保证条线组织的顺序，不开启多线程创建/更新
        this.batchSystemDept(true);
        // 更新组织集合
        initOrganizationCodeList(organizationCodes, false);
    }

    /**
     * 构建本系统部门
     */
    private void buildSystemDept(Organization organization, boolean root) {
        SystemDept systemDept = new SystemDept();
        systemDept.setDeptName(organization.getOrganizationName())
                .setFullName(organization.getShortName())
                .setIdx(organization.getDisplayOrder())
                .setRoot(root)
                .setType(0)
                .setRegionCode(organization.getDivisionCode())
                .setParentId(organization.getParentCode())
                .setUpdateTime(LocalDateTime.now())
                .setId(organization.getOrganizationCode());
        if (ObjectUtil.isEmpty(systemDept.getParentId())) {
            systemDept.setParentId("0");
        }
        systemDeptList.add(systemDept);
        // 保存
        this.batchSystemDept(false);
    }

    /**
     * 构建本系统部门
     */
    private void buildSystemDept(StripLineOrganization stripLineOrganization, boolean root) {
        SystemDept systemDept = new SystemDept();
        systemDept.setDeptName(stripLineOrganization.getOrganizationName())
                .setIdx(Integer.MAX_VALUE >> 16)
                .setRoot(root)
                .setType(1)
                .setRefId(stripLineOrganization.getRefOrganizationCode())
                .setRefName(stripLineOrganization.getRefOrganizationName())
                .setParentId(stripLineOrganization.getParentCode())
                .setUpdateTime(LocalDateTime.now())
                .setId(stripLineOrganization.getOrganizationCode());

        if (ObjectUtil.isEmpty(systemDept.getParentId())) {
            systemDept.setParentId("0");
        }
        systemDeptList.add(systemDept);
        // 保存
        this.batchSystemDept(false);
    }

    /**
     * 构建并保存系统用户
     *
     * @param organizationCode     组织编号
     * @param employeeList         员工列表
     * @param employeeAccountList  账号列表
     * @param orgEmployeePositions 员工职位信息详情列表
     */
    private void buildAndSaveSystemUser(String organizationCode, List<Employee> employeeList, List<EmployeeAccount> employeeAccountList, List<OrgEmployeePosition> orgEmployeePositions) {
        if (ObjectUtil.isEmpty(organizationCode) || ObjectUtil.isEmpty(employeeList)) {
            return;
        }

        Map<String, EmployeeAccount> empAccountMap = IterUtil.toMap(employeeAccountList, EmployeeAccount::getEmployeeCode);
        ConcurrentMap<String, List<OrgEmployeePosition>> orgEmpPositionsMap = orgEmployeePositions.stream().parallel()
                .filter(oep -> StringUtils.hasText(oep.getEmployeeCode()))
                .collect(Collectors.groupingByConcurrent(OrgEmployeePosition::getEmployeeCode));
        // 员工信息
        List<SystemUser> systemUsers = employeeList.stream().parallel()
                .filter(emp -> "A".equals(emp.getStatus()))
                .map(employee -> buildSystemUser(organizationCode, empAccountMap, orgEmpPositionsMap, employee))
                .collect(Collectors.toList());
        systemUserList.addAll(systemUsers);
        // 保存更新
        this.batchSystemUser(false);
        // 组织员工关联信息
        List<SystemDeptUser> systemDeptUsers = employeeList.stream().parallel()
                .filter(emp -> "A".equals(emp.getStatus()))
                .map(employee -> buildSystemDeptUser(organizationCode, orgEmpPositionsMap, employee))
                .collect(Collectors.toList());
        systemDeptUserList.addAll(systemDeptUsers);
        // 保存更新
        this.batchSystemDeptUser(false);
    }

    /**
     * 构建本系统用户
     */
    @NotNull
    private SystemUser buildSystemUser(String organizationCode, Map<String, EmployeeAccount> map, ConcurrentMap<String, List<OrgEmployeePosition>> orgEmpPositionsMap, Employee employee) {
        SystemUser systemUser = new SystemUser();
        // 账号信息
        String employeeCode = employee.getEmployeeCode();
        EmployeeAccount account = map.get(employeeCode);
        String employeeName = employee.getEmployeeName();
        systemUser.setUserName(employeeName);
        if (ObjectUtil.isNotEmpty(account)) {
            systemUser.setUserName(account.getAccountId());
            // accountCode 基本都是手机号
            String accountCode = account.getAccountCode();
            if (PhoneUtil.isPhone(accountCode)) {
                systemUser.setPhone(accountCode);
            }
        }
        // 主要职位信息
        systemUser.setOrderInDept(Integer.MAX_VALUE >> 16);
        Optional.ofNullable(orgEmpPositionsMap.get(employeeCode))
                .orElseGet(Collections::emptyList).stream()
                .filter(gep -> "A".equals(gep.getStatus()))
                .peek(gep -> gep.setMainJob(Optional.ofNullable(gep.getMainJob()).orElse(Boolean.FALSE))
                        .setGovEmpPosJob(Optional.ofNullable(gep.getGovEmpPosJob()).orElse("")))
                .min(Comparator.comparing(OrgEmployeePosition::getMainJob)
                        .reversed().thenComparing(OrgEmployeePosition::getGovEmpPosJob))
                .ifPresent(oep -> systemUser.setGovEmpPosJob(oep.getGovEmpPosJob())
                        .setOrderInDept(Optional.ofNullable(oep.getOrderInOrganization()).orElseGet(systemUser::getOrderInDept))
                );
        // 基础信息
        systemUser.setUserPassword(AuthUtil.getDefaultPassword())
                .setNickName(employeeName)
                .setRealName(employeeName)
                .setDeptId(organizationCode)
                .setDataStatus(StrUtil.equals(employee.getStatus(), "A") ? CommonConstants.YES : CommonConstants.NO)
                .setUpdateTime(LocalDateTime.now())
                .setId(employeeCode);
        return systemUser;
    }

    /**
     * 构建本系统部门用户关联信息
     */
    @NotNull
    private SystemDeptUser buildSystemDeptUser(String organizationCode, ConcurrentMap<String, List<OrgEmployeePosition>> orgEmpPositionsMap, Employee employee) {
        SystemDeptUser systemDeptUser = new SystemDeptUser();
        // 基础信息
        String userId = employee.getEmployeeCode();
        // 主要职位信息
        systemDeptUser.setOrderInDept(Integer.MAX_VALUE >> 16);
        systemDeptUser.setMainJob(false);
        Optional.ofNullable(orgEmpPositionsMap.get(userId))
                .orElseGet(Collections::emptyList).stream()
                .filter(gep -> "A".equals(gep.getStatus()))
                .peek(gep -> gep.setMainJob(Optional.ofNullable(gep.getMainJob()).orElse(Boolean.FALSE))
                        .setGovEmpPosJob(Optional.ofNullable(gep.getGovEmpPosJob()).orElse("")))
                .min(Comparator.comparing(OrgEmployeePosition::getMainJob)
                        .reversed().thenComparing(OrgEmployeePosition::getGovEmpPosJob))
                .ifPresent(oep -> systemDeptUser.setMainJob(Optional.ofNullable(oep.getMainJob()).orElseGet(systemDeptUser::getMainJob))
                        .setGovEmpPosJob(oep.getGovEmpPosJob())
                        .setOrderInDept(Optional.ofNullable(oep.getOrderInOrganization()).orElseGet(systemDeptUser::getOrderInDept))
                );
        systemDeptUser.setUserId(userId)
                .setDeptId(organizationCode)
                .setUserName(employee.getEmployeeName())
                .setUpdateTime(LocalDateTime.now())
                .setId(organizationCode + userId);
        return systemDeptUser;
    }

    /**
     * 批量保存修改部门信息
     */
    private void batchSystemDept(boolean isFinal) {
        if (isFinal) {
            // 最终执行保存/修改
            systemDeptLock.lock();
            try {
                while (!systemDeptList.isEmpty()) {
                    List<SystemDept> sds = new ArrayList<>(systemDeptList);
                    SpringContextHolder.getBean(ISystemDeptService.class).saveOrUpdateBatch(sds,BATCH_MAX_SIZE);
                    systemDeptList.removeAll(sds);
                }
            } finally {
                systemDeptLock.unlock();
            }
            // 接收
            return;
        }
        if (systemDeptList.size() < BATCH_MAX_SIZE) {
            return;
        }
        // 中间尝试保存/修改
        if (systemDeptLock.tryLock()) {
            try {
                while (systemDeptList.size() >= BATCH_MAX_SIZE) {
                    List<SystemDept> sds = new ArrayList<>(systemDeptList);
                    SpringContextHolder.getBean(ISystemDeptService.class).saveOrUpdateBatch(sds,BATCH_MAX_SIZE);
                    systemDeptList.removeAll(sds);
                }
            } finally {
                systemDeptLock.unlock();
            }
        }
    }

    /**
     * 批量保存修改员工信息
     */
    private void batchSystemUser(boolean isFinal) {
        if (isFinal) {
            // 最终执行保存/修改
            systemUserLock.lock();
            try {
                while (!systemUserList.isEmpty()) {
                    List<SystemUser> sus = new ArrayList<>(systemUserList);
                    SpringContextHolder.getBean(ISystemUserService.class).saveOrUpdateBatch(sus,BATCH_MAX_SIZE);
                    systemUserList.removeAll(sus);
                }
            } finally {
                systemUserLock.unlock();
            }
            // 接收
            return;
        }
        // 中间尝试保存/修改
        if (systemUserList.size() < BATCH_MAX_SIZE) {
            return;
        }
        if (systemUserLock.tryLock()) {
            try {
                while (systemUserList.size() >= BATCH_MAX_SIZE) {
                    List<SystemUser> sus = new ArrayList<>(systemUserList);
                    SpringContextHolder.getBean(ISystemUserService.class).saveOrUpdateBatch(sus,BATCH_MAX_SIZE);
                    systemUserList.removeAll(sus);
                }
            } finally {
                systemUserLock.unlock();
            }
        }
    }

    /**
     * 批量保存修改部门员工关联信息 和角色关联信息
     */
    private void batchSystemDeptUser(boolean isFinal) {
        if (isFinal) {
            // 最终执行保存/修改
            systemDeptUserLock.lock();
            try {
                while (!systemDeptUserList.isEmpty()) {
                    List<SystemDeptUser> sdus = new ArrayList<>(systemDeptUserList);
                    SpringContextHolder.getBean(ISystemDeptUserService.class).saveOrUpdateBatch(sdus,BATCH_MAX_SIZE);
                    systemDeptUserList.removeAll(sdus);
                }

            } finally {
                systemDeptUserLock.unlock();
            }
            // 接收
            return;
        }
        // 中间尝试保存/修改
        if (systemDeptUserList.size() < BATCH_MAX_SIZE) {
            return;
        }
        if (systemDeptUserLock.tryLock()) {
            try {
                while (systemDeptUserList.size() >= BATCH_MAX_SIZE) {
                    List<SystemDeptUser> sdus = new ArrayList<>(systemDeptUserList);
                    SpringContextHolder.getBean(ISystemDeptUserService.class).saveOrUpdateBatch(sdus,BATCH_MAX_SIZE);
                    systemDeptUserList.removeAll(sdus);
                }
            } finally {
                systemDeptUserLock.unlock();
            }
        }
    }

    /**
     * 从海政通同步过来的用户，默认赋予用户normal角色
     */
    private void saveUserRole()
    {
        //先删除所有
        SpringContextHolder.getBean(ISystemUserRoleService.class).remove(Wrappers.lambdaQuery(SystemUserRole.class));
        //获取管理员角色，和普通角色的id
        List<SystemMainRole> mainRoles = SpringContextHolder.getBean(ISystemMainRoleService.class).list(Wrappers.lambdaQuery(SystemMainRole.class));
        String adminRoleId=mainRoles.stream().filter(r->r.getEnName().equals("admin")).findFirst().get().getId();
        String normalRoleId=mainRoles.stream().filter(r->r.getEnName().equals("normal")).findFirst().get().getId();
        //保存数据
        List<SystemAdminUser> adminUsers=SpringContextHolder.getBean(ISystemAdminUserService.class).list(Wrappers.lambdaQuery(SystemAdminUser.class));
        List<String> adminPhones=adminUsers.stream().map(SystemAdminUser::getPhone).collect(Collectors.toList());
        List<SystemUser> allUsers=SpringContextHolder.getBean(ISystemUserService.class).list(Wrappers.lambdaQuery(SystemUser.class));
        List<SystemUserRole> surs=allUsers.stream().map(user->{
            SystemUserRole sur=new SystemUserRole();
            sur.setUserId(user.getId())
                    .setRoleType(RoleTypeEnum.SYSTEM.getCode())
                    .setRoleId(normalRoleId);
            if(StringUtils.hasText(user.getPhone()) && adminPhones.contains(user.getPhone()))
            {
                sur.setRoleId(adminRoleId);
            }
            return sur;
        }).collect(Collectors.toList());
        SpringContextHolder.getBean(ISystemUserRoleService.class).saveBatch(surs);
    }

    /**
     * 最后更新组织用户主要部门/职位信息
     */
    private void updateSystemUserJobFinal() {
        ISystemUserService systemUserService = SpringContextHolder.getBean(ISystemUserService.class);
        ISystemDeptUserService systemDeptUserService = SpringContextHolder.getBean(ISystemDeptUserService.class);
        List<SystemUser> systemUsers;
        int pageNo = 1;
        while (true) {
            systemUsers = systemUserService.page(Page.of(pageNo++, BATCH_MAX_SIZE)).getRecords();
            if (CollectionUtils.isEmpty(systemUsers)) {
                break;
            }
            systemUsers = systemUsers.stream().parallel()
                    .peek(su -> {
                        String userId = su.getId();
                        Wrapper<SystemDeptUser> sduWrapper = Wrappers.lambdaQuery(SystemDeptUser.class)
                                .eq(SystemDeptUser::getUserId, userId);
                        List<SystemDeptUser> sdus = systemDeptUserService.list(sduWrapper);
                        su.setOrderInDept(Integer.MAX_VALUE >> 16);
                        Optional.ofNullable(sdus).orElseGet(Collections::emptyList).stream()
                                .peek(sdu -> sdu.setMainJob(Optional.ofNullable(sdu.getMainJob()).orElse(Boolean.FALSE))
                                        .setGovEmpPosJob(Optional.ofNullable(sdu.getGovEmpPosJob()).orElse("")))
                                .min(Comparator.comparing(SystemDeptUser::getMainJob)
                                        .reversed().thenComparing(SystemDeptUser::getGovEmpPosJob))
                                .ifPresent(sdu -> su.setDeptId(sdu.getDeptId())
                                        .setGovEmpPosJob(sdu.getGovEmpPosJob())
                                        .setOrderInDept(Optional.ofNullable(sdu.getOrderInDept()).orElseGet(su::getOrderInDept)));
                    }).collect(Collectors.toList());
            systemUserService.saveOrUpdateBatch(systemUsers);
        }
    }

    /**
     * 最后批量更新用户角色信息（如果没有角色的用户，默认添加演练角色）
     */
    public List<SystemUserRole> getNoRoleSystemUserRole() {
        ISystemRoleService systemRoleService = SpringContextHolder.getBean(ISystemRoleService.class);
        ISystemUserRoleService systemUserRoleService = SpringContextHolder.getBean(ISystemUserRoleService.class);

        LambdaQueryWrapper<SystemRole> roleWrapper = new LambdaQueryWrapper<>();
        roleWrapper.eq(SystemRole::getName, "演练组");
        roleWrapper.last("limit 1");
        SystemRole systemRole = systemRoleService.getOne(roleWrapper);
        List<String> userIdList = systemUserRoleService.selectNoRoleUserId();
        if (CollectionUtil.isNotEmpty(userIdList) && systemRole != null) {
            return userIdList.stream().map(e -> {
                SystemUserRole systemUserRole = new SystemUserRole();
                systemUserRole.setUserId(e);
                systemUserRole.setRoleId(systemRole.getId());
                systemUserRole.setRoleType("2");
                systemUserRole.setId(e);
                systemUserRole.setCreateBy("admin");
                systemUserRole.setUpdateBy("admin");
                return systemUserRole;
            }).collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 清除过旧的组织机构信息和相关用户信息
     */
    private void removeOldSystemDeptAndUser(LocalDateTime rmBeforeDateTime) {
        // 组织信息清除
        List<String> rmDeptIds;
        systemDeptLock.lock();
        try {
            ISystemDeptService systemDeptService = SpringContextHolder.getBean(ISystemDeptService.class);
            Wrapper<SystemDept> noUpdateWrapper = Wrappers.lambdaQuery(SystemDept.class)
                    .select(SystemDept::getId)
                    .lt(SystemDept::getUpdateTime, rmBeforeDateTime);
            // 查询要移除的部门编号
            List<SystemDept> rmDepts = systemDeptService.list(noUpdateWrapper);
            if (CollectionUtils.isEmpty(rmDepts)) {
                return;
            }
            rmDeptIds = rmDepts.stream().parallel().map(SystemDept::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(rmDepts)) {
                return;
            }
            // 清除组织机构信息
            systemDeptService.removeBatchByIds(rmDeptIds, BATCH_MAX_SIZE);
        } finally {
            systemDeptLock.unlock();
        }
        // 清除相应组织员工关联信息
        List<String> rmUserIds;
        systemDeptUserLock.lock();
        try {
            ISystemDeptUserService deptUserService = SpringContextHolder.getBean(ISystemDeptUserService.class);
            // 清除相应组织员工关联信息
            Wrapper<SystemDeptUser> noUpdateWrapper = Wrappers.lambdaQuery(SystemDeptUser.class).in(SystemDeptUser::getDeptId, rmDeptIds);
            rmUserIds = Optional.ofNullable(deptUserService.list(noUpdateWrapper)).orElseGet(Collections::emptyList).stream().parallel()
                    .map(SystemDeptUser::getUserId)
                    .collect(Collectors.toList());
            if (CollectionUtils.isEmpty(rmUserIds)) {
                return;
            }
            deptUserService.remove(noUpdateWrapper);
        } finally {
            systemDeptUserLock.unlock();
        }
        // 员工信息清除
        systemUserLock.lock();
        try {
            // 清除相应员工信息
            Wrapper<SystemUser> rmUserWrapper = Wrappers.lambdaQuery(SystemUser.class).in(SystemUser::getId, rmUserIds);
            SpringContextHolder.getBean(ISystemUserService.class).remove(rmUserWrapper);
        } finally {
            systemUserLock.unlock();
        }
    }

    /**
     * 清除过旧的用户信息
     */
    private void removeOldSystemUser(LocalDateTime rmBeforeDateTime) {
        // 员工信息清除
        List<String> rmUserIds;
        systemUserLock.lock();
        try {
            // 清除相应员工信息
            ISystemUserService systemUserService = SpringContextHolder.getBean(ISystemUserService.class);
            Wrapper<SystemUser> noUpdateWrapper = Wrappers.lambdaQuery(SystemUser.class).lt(SystemUser::getUpdateTime, rmBeforeDateTime);
            rmUserIds = Optional.ofNullable(systemUserService.list(noUpdateWrapper)).orElseGet(Collections::emptyList).stream().parallel()
                    .map(SystemUser::getId)
                    .collect(Collectors.toList());
            if (CollectionUtils.isEmpty(rmUserIds)) {
                return;
            }
            systemUserService.remove(noUpdateWrapper);
        } finally {
            systemUserLock.unlock();
        }
        // 清除相应组织员工关联信息
        systemDeptUserLock.lock();
        try {
            Wrapper<SystemDeptUser> noUpdateWrapper = Wrappers.lambdaQuery(SystemDeptUser.class).lt(SystemDeptUser::getUserId, rmUserIds);
            SpringContextHolder.getBean(ISystemDeptUserService.class).remove(noUpdateWrapper);
        } finally {
            systemDeptUserLock.unlock();
        }
    }


    // ============== 海正通通讯录查询 ==============


    /**
     * 获取通讯录权限范围
     */
    private OapiAuthScopesV2ResponseContent getScopesV2() {
        OapiAuthScopesV2Request oapiAuthScopesV2Request = new OapiAuthScopesV2Request();
        IntelligentGetClient intelligentGetClient = executableClient.newIntelligentGetClient(oapiAuthScopesV2Request.getApiUrl());
        oapiAuthScopesV2Request.setTenantId(zwddProperties.getTenantId());
        OapiAuthScopesV2Response apiResult = intelligentGetClient.get(oapiAuthScopesV2Request);
        if (ObjectUtil.isEmpty(apiResult.getContent())) {
            return null;
        }
        return JSON.parseObject(apiResult.getContent(), OapiAuthScopesV2ResponseContent.class);
    }

    /**
     * 批量根据组织Code查询详情
     */
    private List<Organization> getOrganizationByCodeList(List<String> organizationList) {
        if (ObjectUtil.isEmpty(organizationList)) {
            return CollUtil.list(false);
        }
        int size = organizationList.size();
        if (size > MAX_SIZE) {
            // 数据量过大，折半处理
            int half = size / 2;
            return Stream.of(organizationList.subList(0, half), organizationList.subList(half, size))
                    .map(this::getOrganizationByCodeList)
                    .flatMap(List::stream).collect(Collectors.toList());
        }
        OapiMoziOrganizationListOrganizationsByCodesRequest oapiMoziOrganizationListOrganizationsByCodesRequest = new OapiMoziOrganizationListOrganizationsByCodesRequest();
        IntelligentPostClient intelligentPostClient = executableClient.newIntelligentPostClient(oapiMoziOrganizationListOrganizationsByCodesRequest.getApiUrl());
        oapiMoziOrganizationListOrganizationsByCodesRequest.setOrganizationCodes(organizationList);
        oapiMoziOrganizationListOrganizationsByCodesRequest.setTenantId(zwddProperties.getTenantId());
        OapiMoziOrganizationListOrganizationsByCodesResponse apiResult = intelligentPostClient.post(oapiMoziOrganizationListOrganizationsByCodesRequest);
        if (ObjectUtil.isEmpty(apiResult.getContent()) || ObjectUtil.isEmpty(apiResult.getContent().getData())) {
            return CollUtil.list(false);
        }
        return JSON.parseArray(apiResult.getContent().getData(), Organization.class);
    }

    /**
     * 根据机构编码分页下级机构编码分页
     */
    private List<String> pageSubOrganizationCodeList(int pageNo, String organizationCode) {
        OapiMoziOrganizationPageSubOrganizationCodesRequest oapiMoziOrganizationPageSubOrganizationCodesRequest = new OapiMoziOrganizationPageSubOrganizationCodesRequest();
        IntelligentGetClient intelligentGetClient = executableClient.newIntelligentGetClient(oapiMoziOrganizationPageSubOrganizationCodesRequest.getApiUrl());
        oapiMoziOrganizationPageSubOrganizationCodesRequest.setPageSize(MAX_SIZE);
        oapiMoziOrganizationPageSubOrganizationCodesRequest.setOrganizationCode(organizationCode);
        oapiMoziOrganizationPageSubOrganizationCodesRequest.setPageNo(pageNo);
        oapiMoziOrganizationPageSubOrganizationCodesRequest.setTenantId(zwddProperties.getTenantId());
        OapiMoziOrganizationPageSubOrganizationCodesResponse apiResult = intelligentGetClient.get(oapiMoziOrganizationPageSubOrganizationCodesRequest);
        if (ObjectUtil.isEmpty(apiResult.getContent()) || ObjectUtil.isEmpty(apiResult.getContent().getData())) {
            return CollUtil.list(false);
        }
        return JSON.parseArray(apiResult.getContent().getData(), String.class);
    }

    /**
     * 获取条线通讯录组织详情
     */
    private StripLineOrganization getStripLineOrganizationByCode(String domainCode, String stripLineOrganizationCode) {
        //executableClient保证单例
        IntelligentGetClient intelligentGetClient = executableClient.newIntelligentGetClient("/mozi/stripLineAddressOrg/getDetail");
        OapiMoziStripLineAddressOrgGetDetailRequest oapiMoziStripLineAddressOrgGetDetailRequest = new OapiMoziStripLineAddressOrgGetDetailRequest();
        //域code
        oapiMoziStripLineAddressOrgGetDetailRequest.setDomainCode(domainCode);
        //组织code（获取通讯录权限范围/auth/scopesV2接口返回的stripLineAddressScopes）
        oapiMoziStripLineAddressOrgGetDetailRequest.setOrganizationCode(stripLineOrganizationCode);
        //租户id
        oapiMoziStripLineAddressOrgGetDetailRequest.setTenantId(zwddProperties.getTenantId());
        //获取结果
        OapiMoziStripLineAddressOrgGetDetailResponse apiResult = intelligentGetClient.get(oapiMoziStripLineAddressOrgGetDetailRequest);
        if (ObjectUtil.isEmpty(apiResult.getContent()) || ObjectUtil.isEmpty(apiResult.getContent().getData())) {
            return null;
        }
        return JSON.parseObject(apiResult.getContent().getData(), StripLineOrganization.class);
    }

    /**
     * 分页获取条线通讯录下级组织详情（不含区划）
     */
    private List<StripLineOrganization> pageSubStripLineOrganizationCodeList(int pageNo, String domainCode, String stripLineOrganizationCode) {
        //executableClient保证单例
        IntelligentGetClient intelligentGetClient = executableClient.newIntelligentGetClient("/mozi/stripLineAddressOrg/pageSubOrgs");
        OapiMoziStripLineAddressOrgPageSubOrgsRequest oapiMoziStripLineAddressOrgPageSubOrgsRequest = new OapiMoziStripLineAddressOrgPageSubOrgsRequest();
        //是否返回总数，默认否
        oapiMoziStripLineAddressOrgPageSubOrgsRequest.setReturnTotalSize(false);
        //域code
        oapiMoziStripLineAddressOrgPageSubOrgsRequest.setDomainCode(domainCode);
        //分页大小（默认20，最大100）
        oapiMoziStripLineAddressOrgPageSubOrgsRequest.setPageSize(MAX_SIZE);
        //组织code（获取通讯录权限范围/auth/scopesV2接口返回的stripLineAddressScopes）
        oapiMoziStripLineAddressOrgPageSubOrgsRequest.setOrganizationCode(stripLineOrganizationCode);
        //页码（默认1）
        oapiMoziStripLineAddressOrgPageSubOrgsRequest.setPageNo(pageNo);
        //租户id
        oapiMoziStripLineAddressOrgPageSubOrgsRequest.setTenantId(zwddProperties.getTenantId());
        //获取结果
        OapiMoziStripLineAddressOrgPageSubOrgsResponse apiResult = intelligentGetClient.get(oapiMoziStripLineAddressOrgPageSubOrgsRequest);
        if (ObjectUtil.isEmpty(apiResult.getContent()) || ObjectUtil.isEmpty(apiResult.getContent().getData())) {
            return CollUtil.list(false);
        }
        return JSON.parseArray(apiResult.getContent().getData(), StripLineOrganization.class);
    }

    /**
     * 查询组织下人员详情，包含个人信息和任职信息（为了保证查询效率，分页查询接口控制返回一万条数据）
     */
    private List<Employee> pageEmployeeByOrganizationCodeList(int pageNo, String organizationCode) {
        OapiMoziOrganizationPageOrganizationEmployeePositionsRequest oapiMoziOrganizationPageOrganizationEmployeePositionsRequest = new OapiMoziOrganizationPageOrganizationEmployeePositionsRequest();
        IntelligentGetClient intelligentGetClient = executableClient.newIntelligentGetClient(oapiMoziOrganizationPageOrganizationEmployeePositionsRequest.getApiUrl());
        oapiMoziOrganizationPageOrganizationEmployeePositionsRequest.setPageSize(MAX_SIZE);
        oapiMoziOrganizationPageOrganizationEmployeePositionsRequest.setOrganizationCode(organizationCode);
        oapiMoziOrganizationPageOrganizationEmployeePositionsRequest.setPageNo(pageNo);
        oapiMoziOrganizationPageOrganizationEmployeePositionsRequest.setTenantId(zwddProperties.getTenantId());
        OapiMoziOrganizationPageOrganizationEmployeePositionsResponse apiResult = intelligentGetClient.get(oapiMoziOrganizationPageOrganizationEmployeePositionsRequest);
        if (ObjectUtil.isEmpty(apiResult.getContent()) || ObjectUtil.isEmpty(apiResult.getContent().getData())) {
            return CollUtil.list(false);
        }
        return JSON.parseArray(apiResult.getContent().getData(), Employee.class);
    }

    /**
     * 批量根据员工Code获取员⼯账号ID
     */
    private List<EmployeeAccount> listEmployeeAccountIdList(List<String> employeeCodes) {
        if (ObjectUtil.isEmpty(employeeCodes)) {
            return CollUtil.list(false);
        }
        int size = employeeCodes.size();
        if (size > MAX_SIZE) {
            // 数据量过大，折半处理
            int half = size / 2;
            return Stream.of(employeeCodes.subList(0, half), employeeCodes.subList(half, size))
                    .map(this::listEmployeeAccountIdList)
                    .flatMap(List::stream).collect(Collectors.toList());
        }
        OapiMoziEmployeeListEmployeeAccountIdsRequest oapiMoziEmployeeListEmployeeAccountIdsRequest = new OapiMoziEmployeeListEmployeeAccountIdsRequest();
        IntelligentGetClient intelligentGetClient = executableClient.newIntelligentGetClient(oapiMoziEmployeeListEmployeeAccountIdsRequest.getApiUrl());
        oapiMoziEmployeeListEmployeeAccountIdsRequest.setTenantId(zwddProperties.getTenantId());
        oapiMoziEmployeeListEmployeeAccountIdsRequest.setEmployeeCodes(employeeCodes);
        OapiMoziEmployeeListEmployeeAccountIdsResponse apiResult = intelligentGetClient.get(oapiMoziEmployeeListEmployeeAccountIdsRequest);
        if (ObjectUtil.isEmpty(apiResult.getContent()) || ObjectUtil.isEmpty(apiResult.getContent().getData())) {
            return CollUtil.list(false);
        }
        return JSON.parseArray(apiResult.getContent().getData(), EmployeeAccount.class);
    }

    /**
     * 批量获取组织下员工职位
     */
    private List<OrgEmployeePosition> listGovEmployeePositions(String organizationCode, List<String> employeeCodes) {
        int size = employeeCodes.size();
        if (size > MAX_SIZE) {
            // 数据量过大，折半处理
            int half = size / 2;
            return Stream.of(employeeCodes.subList(0, half), employeeCodes.subList(half, size))
                    .map(ecs -> listGovEmployeePositions(organizationCode, ecs))
                    .flatMap(List::stream).collect(Collectors.toList());
        }
        OapiMoziEmployeeListOrgEmployeePositionsByCodesRequest oapiMoziEmployeeListOrgEmployeePositionsByCodesRequest = new OapiMoziEmployeeListOrgEmployeePositionsByCodesRequest();
        IntelligentPostClient intelligentPostClient = executableClient.newIntelligentPostClient(oapiMoziEmployeeListOrgEmployeePositionsByCodesRequest.getApiUrl());
        //设置参数
        oapiMoziEmployeeListOrgEmployeePositionsByCodesRequest.setEmployeeCodes(employeeCodes);
        oapiMoziEmployeeListOrgEmployeePositionsByCodesRequest.setOrganizationCode(organizationCode);
        oapiMoziEmployeeListOrgEmployeePositionsByCodesRequest.setTenantId(zwddProperties.getTenantId());
        //调用API
        OapiMoziEmployeeListOrgEmployeePositionsByCodesResponse apiResult = intelligentPostClient.post(oapiMoziEmployeeListOrgEmployeePositionsByCodesRequest);
        if (ObjectUtil.isEmpty(apiResult.getContent()) || ObjectUtil.isEmpty(apiResult.getContent().getData())) {
            return CollUtil.list(false);
        }
        return JSON.parseArray(apiResult.getContent().getData(), OrgEmployeePosition.class);
    }

}
